﻿using Aliyun.OSS;
using Aliyun.OSS.Common;
using Aliyun.OSS.Util;
using CDW.Library;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Input;

namespace DW.Library
{
    public class OSSHelper
    {

        static string accessKeyId = "LTAI5tFRGqVrSxugruUpRwYt";
        static string accessKeySecret = "xffRAFqSrBhPGHHa0GQjmvanAZaeqV\n\n";
        static string endpoint = "oss-cn-beijing.aliyuncs.com";
        public static string bucketName = "cloudusb";

        static OssClient client = new OssClient(endpoint, accessKeyId, accessKeySecret);
        static AutoResetEvent _event = new AutoResetEvent(false);

        public static void Init(string _bucketName)
        {
            bucketName = _bucketName;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="localFilePath">本地文件路径</param>
        public static bool PutObjectFromFileWithTimeout(string localFilePath, string putDir)
        {
            var _configuration = new ClientConfiguration();
            _configuration.ConnectionTimeout = 1000 * 60 * 5;// 最多等待5分钟
            var _client = new OssClient(endpoint, accessKeyId, accessKeySecret, _configuration);

            string key = Path.GetFileName(localFilePath);
            if (!string.IsNullOrEmpty(putDir))
            {
                key = $"{putDir}/{Path.GetFileName(localFilePath)}";
            }

            try
            {
                _client.PutObject(bucketName, key, localFilePath);
                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return false;
        }

        public static Action<double> PutEvent;
        public static Action<double> GutEvent;

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="localFilePath">本地文件路径</param>
        public static async Task<bool> PutObjectProgress(string localFilePath, string putDir)
        {
            var _configuration = new ClientConfiguration();
            _configuration.ConnectionTimeout = 1000 * 60 * 5;// 最多等待5分钟
            var _client = new OssClient(endpoint, accessKeyId, accessKeySecret, _configuration);

            string key = Path.GetFileName(localFilePath);
            if (!string.IsNullOrEmpty(putDir))
            {
                key = $"{putDir}/{Path.GetFileName(localFilePath)}";
            }

            try
            {
                if (File.Exists(localFilePath))
                {
                    FileInfo fi = new FileInfo(localFilePath);
                    if (fi.IsReadOnly)
                    {
                        fi.IsReadOnly = false;
                    }
                }

                using (var fs = File.Open(localFilePath, FileMode.Open))
                {
                    string result = "Notice user: put object finish";
                    var putObjectRequest = new PutObjectRequest(bucketName, key, fs);
                    putObjectRequest.StreamTransferProgress += streamProgressCallback;
                    // 使用 Task.Run 包装同步方法实现异步
                    await Task.Run(() => _client.PutObject(putObjectRequest));
                    //_event.WaitOne();
                }
                Console.WriteLine("Put object:{0} succeeded", key);
                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return false;
        }
        private static void PutObjectCallback(IAsyncResult ar)
        {
            try
            {
                //client.EndPutObject(ar);
                //Console.WriteLine(ar.AsyncState as string);
                //Console.WriteLine("Put object succeeded");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                //_event.Set();
            }
        }
        // 获取上传进度。
        private static void streamProgressCallback(object sender, StreamTransferProgressArgs args)
        {
            double processValue = args.TransferredBytes * 100 / args.TotalBytes;
            Trace.WriteLine($"ProgressCallback - Progress: {processValue}%" +
                $", TotalBytes:{args.TotalBytes}" +
                $", TransferredBytes:{args.TransferredBytes} "
              );
            PutEvent?.Invoke(processValue);
        }

        /// <summary>
        /// 下载单个文件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dir">下载路径</param>
        public static async Task<bool> GetObject(string key, string downloadPath)
        {
            try
            {
                if (!Directory.Exists(Path.GetDirectoryName(downloadPath)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(downloadPath));
                }
                await Task.Run(() =>
                {
                    var result = client.GetObject(bucketName, key);

                    using (var requestStream = result.Content)
                    {
                        using (var fs = File.Open(downloadPath, FileMode.OpenOrCreate))
                        {
                            long totalBytes = result.Metadata.ContentLength;
                            long transferredBytes = 0;
                            int length = 4 * 1024;
                            var buf = new byte[length];
                            do
                            {
                                length = requestStream.Read(buf, 0, length);
                                transferredBytes += length;
                                fs.Write(buf, 0, length);
                                if (GutEvent != null)
                                {
                                    double percent = transferredBytes * 100.0 / totalBytes;
                                    GutEvent(percent);
                                }
                            } while (length != 0);
                        }
                    }
                });
                Console.WriteLine("Get object succeeded");
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 异步下载单个文件
        /// </summary>
        /// <param name="key">OSS文件Key</param>
        /// <param name="downloadPath">本地下载路径</param>
        /// <returns>Task</returns>
        public static async Task GetObjectAsync(string key, string downloadPath)
        {
            try
            {
                string? dir = Path.GetDirectoryName(downloadPath);
                if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                // 使用 Task.Run 包装同步方法实现异步
                await Task.Run(() =>
                {
                    var result = client.GetObject(bucketName, key);
                    using (var requestStream = result.Content)
                    using (var fs = File.Open(downloadPath, FileMode.OpenOrCreate))
                    {
                        int length = 4 * 1024;
                        var buf = new byte[length];
                        do
                        {
                            length = requestStream.Read(buf, 0, length);
                            fs.Write(buf, 0, length);
                        } while (length != 0);
                    }
                });

                Console.WriteLine("Get object succeeded");
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }
        public static List<FileInfoModel> GetAllObjectDetail(string dirPath)
        {
            List<FileInfoModel> fileNames = new List<FileInfoModel>();
            try
            {
                var result = client.ListObjects(bucketName);
                foreach (var summary in result.ObjectSummaries)
                {
                    if (string.IsNullOrEmpty(dirPath) || summary.Key.StartsWith(dirPath, StringComparison.OrdinalIgnoreCase))
                    {
                        FileInfoModel fileInfoModel = new FileInfoModel
                        {
                            FileName = Path.GetFileName(summary.Key),
                            FilePath = summary.Key,
                            Size = summary.Size,
                            Type = Path.GetExtension(summary.Key),
                            LastModified = TimeZoneInfo.ConvertTimeFromUtc(summary.LastModified, TimeZoneInfo.Local)
                        };
                        fileNames.Add(fileInfoModel);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                MessageBox.Show($"获取文件列表失败：{ex.Message}");
            }
            return fileNames;
        }
        public static List<string> GetAllObject(string dirPath)
        {
            List<string> fileNames = new List<string>();
            try
            {
                var result = client.ListObjects(bucketName);
                foreach (var summary in result.ObjectSummaries)
                {
                    if (string.IsNullOrEmpty(dirPath) || summary.Key.StartsWith(dirPath, StringComparison.OrdinalIgnoreCase))
                    {
                        fileNames.Add(summary.Key);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
                MessageBox.Show($"获取文件列表失败：{ex.Message}");
            }
            return fileNames;
        }

        /// <summary>
        /// 获取文件内容
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dir">下载目录</param>
        public static string GetObjectContent(string key)
        {
            string content = $"";
            try
            {
                var result = client.GetObject(bucketName, key);

                using (var requestStream = result.Content)
                {
                    if (requestStream != null)
                    {
                        // 将Stream对象转换为字符串
                        using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
                        {
                            string readContent = reader.ReadToEnd();
                            if (!string.IsNullOrEmpty(readContent))
                            {
                                content = readContent;
                            }
                        }
                    }

                }
                return content;
                Console.WriteLine("Get object succeeded");
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return content;
        }
        public static string GetFileUrl(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return null;
            }
            // 生成URL，默认有效期为1小时
            var url = client.GeneratePresignedUri(bucketName, filePath, DateTime.Now.AddHours(1));
            return url.ToString();
        }   

        public static string GetObjectUrl(List<string> FilePaths)
        {
            // 定义返回值
            string result = string.Empty;
            try
            {
                if (FilePaths == null || FilePaths.Count == 0)
                {
                    Console.WriteLine("No files to generate URLs for.");
                    return null;
                }

                foreach (var filePath in FilePaths)
                {
                    // 检查每个文件是否存在
                    if (!DoesObjectExist(filePath).GetValueOrDefault())
                    {
                        Console.WriteLine($"File {filePath} does not exist in OSS bucket {bucketName}.");
                        return null;
                    }
                    // 生成URL，默认有效期为1小时
                    var url = GetFileUrl(filePath);
                    result += $"{filePath}：\r\n{url}\r\n\r\n";
                }

            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return result;
        }
        public static bool? DeleteObjects(List<string> keys)
        {
            try
            {
                var request = new DeleteObjectsRequest(bucketName, keys, false);
                client.DeleteObjects(request);
                return true;
                Console.WriteLine("Delete objects succeeded");
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return null;
        }
        /// <summary>
        /// 判断文件是否存在
        /// </summary>
        /// <param name="key">服务器文件路径</param>
        public static bool? DoesObjectExist(string key)
        {
            try
            {
                var exist = client.DoesObjectExist(bucketName, key);
                return exist;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return null;
        }
    }
}
